﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.DataAccess;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;
using System.Transactions;

namespace Wyn.PMS.Common.NightAudit
{
    internal class LedgerTotal
    {
        private static readonly IUnityContainer container = UnityContainerService.GetContainer();
        
        public void Total(HotelBizDay bizDay,IList<Account> accounts)
        {
            INaLedgerTotalRepository totalRepository = container.Resolve<INaLedgerTotalRepository>();

            ILedgerRepository ledgerRepository = container.Resolve<ILedgerRepository>();

            string hotelId = bizDay.HotelID;

            DateTime yesterBizDay = bizDay.BizDay.AddDays(-1);

            DateTime todayBizDay = bizDay.BizDay;

            Expression<Func<NaLedgerTotal, bool>> exp = n => n.HotelID == hotelId && n.BizDay == yesterBizDay;

            var yesterdayTotals = totalRepository.BatchFind(hotelId, exp);

            var allLeger = ledgerRepository.BatchFind(hotelId, r => r.IsValid);

            IList<Ledger> parentLedgers = allLeger.Where(r => r.LedgerParentCode == LedgerCode.根代码).ToList();

            IList<Ledger> subLedgers = allLeger.Where(r => r.LedgerParentCode != LedgerCode.根代码).ToList();

            IList<NaLedgerTotal> ledgerTotals = new List<NaLedgerTotal>();

            foreach (var ledger in subLedgers)
            {
                var yesterTotal = yesterdayTotals.FirstOrDefault(t => t.LedgerCode == ledger.LedgerCode);

                var ledgerAccounts = accounts.Where(a => a.LedgerCode == ledger.LedgerCode);

                var total = BuildLedgerTotal(yesterTotal, ledgerAccounts, ledger, todayBizDay, hotelId);

                ledgerTotals.Add(total);
            }

            foreach (var ledger in parentLedgers)
            {
                var parentTotals = ledgerTotals.Where(t => t.ParentCode == ledger.LedgerCode);

                var total = BuildParentTotal(parentTotals, hotelId, todayBizDay, ledger);

                ledgerTotals.Add(total);
            }

            //按租类统计
            OperationAnalysis analysis = new OperationAnalysis();
            
            var checkinTyps = analysis.GetCheckInTypes();

            foreach(var type in checkinTyps)
            {
                var yesterTotal = yesterdayTotals.FirstOrDefault(t => t.LedgerCode == type.Key);

                var checkInAccounts = accounts.Where(a => a.CheckInType == type.Key && a.LedgerCode == LedgerCode.标准房租);

                var total = BuildCheckInTypeTotal(yesterTotal, checkInAccounts, type.Key, type.Value, todayBizDay, hotelId);

                ledgerTotals.Add(total);
            }

            if (bizDay.Status != EnumHelper.GetCode(NightAuditCode.Status.E)
                || (bizDay.Status == EnumHelper.GetCode(NightAuditCode.Status.E)
                && bizDay.Steping == (int)NightAuditCode.Steping.LedgerTotal))
            {
                bizDay.Status = EnumHelper.GetCode(NightAuditCode.Status.I);

                //using (TransactionScope scope = new TransactionScope())
                //{
                totalRepository.BatchInsert(hotelId, ledgerTotals);

                //  scope.Complete();
                //}
            }

        }

        private NaLedgerTotal BuildCheckInTypeTotal(NaLedgerTotal yesterTotal, IEnumerable<Account> checkInAccounts, string checkInType, string checkInName, DateTime todayBizDay, string hotelId)
        {
            var total = new NaLedgerTotal();

            total.BizDay = todayBizDay;

            total.HotelID = hotelId;

            total.LedgerCode = checkInType;

            total.LedgerName = checkInName;

            total.LedgerType = AccountType.D;

            total.ParentCode = LedgerCode.入住类型之父;

            if (checkInAccounts != null && checkInAccounts.Any())
            {
                total.TodayOccur = checkInAccounts.Sum(l => l.Balance);

                total.TodayRecede = Math.Abs(checkInAccounts.Where(l => l.Balance < 0).Sum(l => l.Balance));

                total.TodayActualMoney = checkInAccounts.Sum(l => l.ActualMoney);

                total.ItemCount = checkInAccounts.Count();
            }

            //月金额汇总
            if (yesterTotal != null && yesterTotal.BizDay.Month == todayBizDay.Month)
            {
                total.MonthBalance = yesterTotal.MonthBalance + total.TodayOccur;
                total.MonthActualMoney = yesterTotal.MonthActualMoney + total.TodayActualMoney;
                total.TotalBanlance = yesterTotal.TotalBanlance + total.TodayOccur;
            }
            else
            {
                total.MonthBalance = total.TodayOccur;
                total.MonthActualMoney = total.TodayActualMoney;
                total.TotalBanlance = total.TodayOccur;
            }

            //年金额汇总
            if (yesterTotal != null && yesterTotal.BizDay.Year == todayBizDay.Year)
            {
                total.YearBalance = yesterTotal.YearBalance + total.TodayOccur;
                total.YearActualMoney = yesterTotal.YearActualMoney + total.TodayActualMoney;
            }
            else
            {
                total.YearBalance = total.TodayOccur;
                total.YearActualMoney = total.TodayActualMoney;
            }

            return total;
        }

        private NaLedgerTotal BuildLedgerTotal(NaLedgerTotal yesterTotal, IEnumerable<Account> ledgerAccounts, Ledger ledger, DateTime todayBizDay, string hotelId)
        {
            var total = new NaLedgerTotal();

            if (ledgerAccounts != null && ledgerAccounts.Any())
            {
                total.TodayOccur = ledgerAccounts.Sum(l => l.Balance);

                total.TodayRecede = Math.Abs(ledgerAccounts.Where(l => l.Balance < 0).Sum(l => l.Balance));

                total.TodayActualMoney = ledgerAccounts.Sum(l => l.ActualMoney);

                total.ItemCount = ledgerAccounts.Count();
            }

            //月金额汇总
            if (yesterTotal != null && yesterTotal.BizDay.Month == todayBizDay.Month)
            {
                total.MonthBalance = yesterTotal.MonthBalance + total.TodayOccur;
                total.MonthActualMoney = yesterTotal.MonthActualMoney + total.TodayActualMoney;
                total.TotalBanlance = yesterTotal.TotalBanlance + total.TodayOccur;
            }
            else
            {
                total.MonthBalance = total.TodayOccur;
                total.MonthActualMoney = total.TodayActualMoney;
                total.TotalBanlance =  total.TodayOccur;
            }

            //年金额汇总
            if (yesterTotal != null && yesterTotal.BizDay.Year == todayBizDay.Year)
            {
                total.YearBalance = yesterTotal.YearBalance + total.TodayOccur;
                total.YearActualMoney = yesterTotal.YearActualMoney + total.TodayActualMoney;
            }
            else
            {
                total.YearBalance = total.TodayOccur;
                total.YearActualMoney = total.TodayActualMoney;
            }

            total.BizDay = todayBizDay;

            total.HotelID = hotelId;

            total.LedgerCode = ledger.LedgerCode;

            total.LedgerName = ledger.LedgerName;

            total.LedgerType = ledger.LedgerType;

            total.ParentCode = ledger.LedgerParentCode;

            return total;
        }

        private NaLedgerTotal BuildParentTotal(IEnumerable<NaLedgerTotal> ledgerTotals, string hotelId, DateTime bizDay, Ledger ledger)
        {
            var total = new NaLedgerTotal();

            total.BizDay = bizDay;

            total.HotelID = hotelId;

            total.LedgerCode = ledger.LedgerCode;

            total.LedgerName = ledger.LedgerName;

            total.LedgerType = ledger.LedgerType;

            total.ParentCode = ledger.LedgerParentCode;

            if (ledgerTotals.Any())
            {
                total.ItemCount = ledgerTotals.Sum(t=>t.ItemCount);

                total.TodayOccur = ledgerTotals.Sum(t => t.TodayOccur);

                total.TodayRecede = ledgerTotals.Sum(t => t.TodayRecede);

                total.MonthBalance = ledgerTotals.Sum(t => t.MonthBalance);

                total.YearBalance = ledgerTotals.Sum(t => t.YearBalance);

                total.TodayActualMoney = ledgerTotals.Sum(t => t.TodayActualMoney);

                total.MonthActualMoney = ledgerTotals.Sum(t => t.MonthActualMoney);

                total.YearActualMoney = ledgerTotals.Sum(t => t.YearActualMoney);
            }

            return total;
        }
    
        
    }
}
